#!/bin/bash

# 证书管理系统 Docker 生产环境部署脚本
# 功能：从 production-code 仓库部署 Docker 容器化系统

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'

# 日志函数
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_step() { echo -e "${PURPLE}[STEP]${NC} $1"; }

# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 部署根目录
DEPLOY_ROOT="/www/cert_manager"
# 源码目录
SOURCE_DIR="$SCRIPT_DIR/source"
# 备份目录
BACKUP_DIR="$DEPLOY_ROOT/backup/install"

# 生产代码仓库（使用HTTPS地址）
PRODUCTION_REPO_GITEE="https://gitee.com/zhuxbo/production-code.git"
PRODUCTION_REPO_GITHUB="https://github.com/zhuxbo/production-code.git"

# 默认端口
WEB_PORT=80

# 解析命令行参数
FORCE_REPO=""
CLEAN_INSTALL=false
while [[ $# -gt 0 ]]; do
    case $1 in
        gitee)
            FORCE_REPO="gitee"
            log_info "强制使用 Gitee 仓库"
            shift
            ;;
        github)
            FORCE_REPO="github"
            log_info "强制使用 GitHub 仓库"
            shift
            ;;
        clean)
            CLEAN_INSTALL=true
            log_info "执行全新安装（清理旧数据）"
            shift
            ;;
        --port|-p)
            WEB_PORT="$2"
            log_info "Web 端口设置为: $WEB_PORT"
            shift 2
            ;;
        -h|help)
            echo "用法: $0 [选项]"
            echo "选项:"
            echo "  gitee        - 强制使用 Gitee 仓库"
            echo "  github       - 强制使用 GitHub 仓库"
            echo "  clean        - 清理旧数据后全新安装"
            echo "  --port, -p   - 指定 Web 端口（默认: 80）"
            echo "  help         - 显示此帮助信息"
            echo ""
            echo "示例:"
            echo "  $0                    # 使用默认设置"
            echo "  $0 --port 8080        # 使用 8080 端口"
            echo "  $0 gitee clean        # 从 Gitee 全新安装"
            exit 0
            ;;
        *)
            log_warning "未知参数: $1"
            shift
            ;;
    esac
done

# 检查 Docker 和 Docker Compose
check_docker() {
    log_info "检查 Docker 环境..."
    
    if ! command -v docker &> /dev/null; then
        log_error "Docker 未安装，请先安装 Docker"
        log_info "安装命令: curl -fsSL https://get.docker.com | sh"
        exit 1
    fi
    
    if ! docker compose version &> /dev/null && ! docker-compose --version &> /dev/null; then
        log_error "Docker Compose 未安装"
        log_info "请安装 Docker Compose v2 或更高版本"
        exit 1
    fi
    
    # 检查 Docker 服务是否运行
    if ! docker info &> /dev/null; then
        log_error "Docker 服务未运行"
        log_info "启动命令: sudo systemctl start docker"
        exit 1
    fi
    
    log_success "Docker 环境检查通过"
}

# 创建必要的目录
create_directories() {
    log_info "创建目录结构..."
    mkdir -p "$SOURCE_DIR" "$BACKUP_DIR" "$DEPLOY_ROOT/backup/keeper" 2>/dev/null
    mkdir -p "$DEPLOY_ROOT"/{mysql/data,redis/data,nginx/logs,backend/storage/logs} 2>/dev/null
}

# 拉取生产代码
pull_production_code() {
    log_info "获取生产代码..."
    
    cd "$SOURCE_DIR"
    
    if [ -d "production-code" ]; then
        cd production-code
        
        # 如果指定了强制仓库，先切换到指定仓库
        if [ -n "$FORCE_REPO" ]; then
            if [ "$FORCE_REPO" = "gitee" ]; then
                log_info "切换到 Gitee 仓库..."
                git remote set-url origin "$PRODUCTION_REPO_GITEE"
            elif [ "$FORCE_REPO" = "github" ]; then
                log_info "切换到 GitHub 仓库..."
                git remote set-url origin "$PRODUCTION_REPO_GITHUB"
            fi
        fi
        
        # 尝试从当前 origin 拉取
        if ! git fetch origin >/dev/null 2>&1; then
            if [ -n "$FORCE_REPO" ]; then
                # 如果指定了强制仓库但失败，直接报错
                log_error "无法从指定的 $FORCE_REPO 仓库拉取代码"
                exit 1
            fi
            
            log_warning "从当前仓库拉取失败，尝试切换仓库..."
            # 获取当前 origin URL
            local current_url=$(git remote get-url origin 2>/dev/null || echo "")
            
            # 尝试切换到备用仓库
            if [[ "$current_url" == *"gitee.com"* ]]; then
                log_info "切换到 GitHub 仓库..."
                git remote set-url origin "$PRODUCTION_REPO_GITHUB"
            else
                log_info "切换到 Gitee 仓库..."
                git remote set-url origin "$PRODUCTION_REPO_GITEE"
            fi
            
            # 再次尝试拉取
            if ! git fetch origin >/dev/null 2>&1; then
                log_error "无法从任何仓库拉取代码"
                exit 1
            fi
        fi
        git reset --hard origin/main >/dev/null 2>&1
    else
        # 首次克隆
        local clone_success=false
        
        if [ -n "$FORCE_REPO" ]; then
            # 如果指定了强制仓库，只尝试指定的仓库
            if [ "$FORCE_REPO" = "gitee" ]; then
                log_info "从 Gitee 克隆..."
                if git clone "$PRODUCTION_REPO_GITEE" production-code >/dev/null 2>&1; then
                    clone_success=true
                    log_success "从 Gitee 克隆成功"
                else
                    log_error "无法从 Gitee 克隆代码"
                    exit 1
                fi
            elif [ "$FORCE_REPO" = "github" ]; then
                log_info "从 GitHub 克隆..."
                if git clone "$PRODUCTION_REPO_GITHUB" production-code >/dev/null 2>&1; then
                    clone_success=true
                    log_success "从 GitHub 克隆成功"
                else
                    log_error "无法从 GitHub 克隆代码"
                    exit 1
                fi
            fi
        else
            # 未指定强制仓库，按原逻辑尝试
            # 优先尝试 Gitee（国内通常更快）
            log_info "尝试从 Gitee 克隆..."
            if git clone "$PRODUCTION_REPO_GITEE" production-code >/dev/null 2>&1; then
                clone_success=true
                log_success "从 Gitee 克隆成功"
            else
                log_warning "Gitee 克隆失败，尝试 GitHub..."
                if git clone "$PRODUCTION_REPO_GITHUB" production-code >/dev/null 2>&1; then
                    clone_success=true
                    log_success "从 GitHub 克隆成功"
                fi
            fi
            
            if [ "$clone_success" = false ]; then
                log_error "无法从任何仓库克隆代码"
                exit 1
            fi
        fi
        
        cd production-code
    fi
    
    # 读取版本信息
    if [ -f "config.json" ]; then
        if command -v jq >/dev/null 2>&1; then
            VERSION=$(jq -r '.version' config.json 2>/dev/null || true)
        else
            VERSION=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"\n]*\)".*/\1/p' config.json | head -n1)
        fi
        [ -z "$VERSION" ] && VERSION="unknown"
        log_success "版本: $VERSION"
    fi
    
    cd "$SCRIPT_DIR"
}

# 清理旧的 Docker 环境
clean_docker_environment() {
    if [ "$CLEAN_INSTALL" = true ]; then
        log_warning "清理旧的 Docker 环境..."
        
        # 停止并删除容器
        docker compose down --remove-orphans 2>/dev/null || true
        docker stop $(docker ps -aq --filter name=cert-) 2>/dev/null || true
        docker rm $(docker ps -aq --filter name=cert-) 2>/dev/null || true
        
        # 删除镜像
        docker rmi $(docker images --filter reference="*cert*" -q) 2>/dev/null || true
        
        # 清理卷和网络
        docker volume ls -q --filter name=cert | xargs -r docker volume rm 2>/dev/null || true
        docker network ls -q --filter name=cert | xargs -r docker network rm 2>/dev/null || true
        
        # 删除部署目录
        if [ -d "$DEPLOY_ROOT" ]; then
            log_info "删除部署目录: $DEPLOY_ROOT"
            rm -rf "$DEPLOY_ROOT"
        fi
        
        log_success "清理完成"
    fi
}

# 部署文件
deploy_files() {
    log_info "部署系统文件..."
    
    # 从源码目录复制文件
    SOURCE_PATH="$SOURCE_DIR/production-code"
    
    # 复制后端代码
    if [ -d "$SOURCE_PATH/backend" ]; then
        cp -r "$SOURCE_PATH/backend" "$DEPLOY_ROOT/" 2>/dev/null
    fi
    
    # 复制前端代码
    if [ -d "$SOURCE_PATH/frontend" ]; then
        cp -r "$SOURCE_PATH/frontend" "$DEPLOY_ROOT/" 2>/dev/null
    fi
    
    # 复制 nginx 配置
    if [ -d "$SOURCE_PATH/nginx" ]; then
        cp -r "$SOURCE_PATH/nginx" "$DEPLOY_ROOT/" 2>/dev/null
    fi
    
    # 复制构建信息文件
    if [ -f "$SOURCE_PATH/config.json" ]; then
        cp "$SOURCE_PATH/config.json" "$DEPLOY_ROOT/"
    fi
    
    log_success "文件部署完成"
}

# 生成 Docker Compose 配置
generate_docker_compose() {
    log_info "生成 Docker Compose 配置..."
    
    cat > "$SCRIPT_DIR/docker-compose.yml" << 'EOF'
services:
  # MySQL 数据库
  mysql:
    image: mysql:8.0
    container_name: cert-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root@2024}
      MYSQL_DATABASE: ${MYSQL_DATABASE:-cert_manager}
      MYSQL_USER: ${MYSQL_USER:-cert_user}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD:-cert@2024}
      TZ: Asia/Shanghai
    volumes:
      - /www/cert_manager/mysql/data:/var/lib/mysql
    networks:
      - cert-network
    restart: unless-stopped
    command: 
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-authentication-plugin=mysql_native_password
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: cert-redis
    volumes:
      - /www/cert_manager/redis/data:/data
    networks:
      - cert-network
    restart: unless-stopped
    command: redis-server --appendonly yes --bind 0.0.0.0 --protected-mode no
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  # PHP-FPM (使用官方镜像，无需构建)
  php:
    image: php:8.3-fpm
    container_name: cert-php
    volumes:
      - /www/cert_manager:/www/cert_manager
      - ./dockerfiles/php/php.ini:/usr/local/etc/php/conf.d/custom.ini:ro
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - cert-network
    restart: unless-stopped
    environment:
      - TZ=Asia/Shanghai
    working_dir: /www/cert_manager/backend
    command: >
      sh -c "
      docker-php-ext-install pdo_mysql bcmath pcntl &&
      pecl install redis && docker-php-ext-enable redis &&
      php-fpm
      "

  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    container_name: cert-nginx
    ports:
      - "${WEB_PORT}:${WEB_PORT}"
      - "${NGINX_SSL_PORT:-443}:443"
    volumes:
      - /www/cert_manager:/www/cert_manager:ro
      - /www/cert_manager/nginx/logs:/var/log/nginx
      - ./nginx/cert-manager.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
    networks:
      - cert-network
    restart: unless-stopped

  # 队列处理器
  queue:
    image: php:8.3-cli
    container_name: cert-queue
    volumes:
      - /www/cert_manager:/www/cert_manager
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - cert-network
    restart: unless-stopped
    working_dir: /www/cert_manager/backend
    command: >
      sh -c "
      docker-php-ext-install pdo_mysql bcmath pcntl &&
      pecl install redis && docker-php-ext-enable redis &&
      php artisan queue:work --queue Task --tries 3 --delay 5 --max-jobs 1000 --max-time 3600 --memory 128 --timeout 60 --sleep 3
      "

  # 定时任务
  scheduler:
    image: php:8.3-cli
    container_name: cert-scheduler
    volumes:
      - /www/cert_manager:/www/cert_manager
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - cert-network
    restart: unless-stopped
    working_dir: /www/cert_manager/backend
    entrypoint: >
      sh -c "
      docker-php-ext-install pdo_mysql bcmath pcntl &&
      pecl install redis && docker-php-ext-enable redis &&
      while true; do
        php artisan schedule:run --verbose --no-interaction &
        sleep 60
      done
      "

networks:
  cert-network:
    driver: bridge
    name: cert-network
EOF
    
    log_success "Docker Compose 配置生成完成"
}

# 生成 Nginx 配置
generate_nginx_config() {
    log_info "生成 Nginx 配置..."
    
    mkdir -p "$SCRIPT_DIR/nginx"
    
    cat > "$SCRIPT_DIR/nginx/cert-manager.conf" << EOF
server {
    listen $WEB_PORT;
    server_name localhost;
    
    # 项目根目录
    root /www/cert_manager;
    
    # 引入生产代码中的 nginx 配置
    include /www/cert_manager/nginx/manager.conf;
}
EOF
    
    log_success "Nginx 配置生成完成"
}

# 生成 PHP 配置
generate_php_config() {
    log_info "生成 PHP 配置..."
    
    mkdir -p "$SCRIPT_DIR/dockerfiles/php"
    
    cat > "$SCRIPT_DIR/dockerfiles/php/php.ini" << 'EOF'
[PHP]
memory_limit = 256M
max_execution_time = 300
post_max_size = 50M
upload_max_filesize = 50M
max_file_uploads = 20

[Date]
date.timezone = Asia/Shanghai

[opcache]
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1
EOF
    
    log_success "PHP 配置生成完成"
}

# 初始化 Laravel
initialize_laravel() {
    log_info "初始化 Laravel..."
    
    cd "$DEPLOY_ROOT/backend"
    
    # 创建 .env 文件
    if [ ! -f ".env" ]; then
        cp .env.example .env 2>/dev/null || true
        
        # 更新数据库配置
        sed -i "s/DB_HOST=.*/DB_HOST=mysql/" .env
        sed -i "s/DB_DATABASE=.*/DB_DATABASE=cert_manager/" .env
        sed -i "s/DB_USERNAME=.*/DB_USERNAME=cert_user/" .env
        sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=cert@2024/" .env
        
        # 更新 Redis 配置
        sed -i "s/REDIS_HOST=.*/REDIS_HOST=redis/" .env
        sed -i "s/REDIS_PASSWORD=.*/REDIS_PASSWORD=null/" .env
    fi
    
    # 设置权限
    chmod -R 755 storage bootstrap/cache
    
    cd "$SCRIPT_DIR"
}

# 启动服务
start_services() {
    log_info "启动 Docker 服务..."
    
    cd "$SCRIPT_DIR"
    
    # 使用 docker compose 启动
    if command -v docker-compose &> /dev/null; then
        docker-compose up -d
    else
        docker compose up -d
    fi
    
    # 等待服务启动
    log_info "等待服务启动..."
    sleep 10
    
    # 执行 Laravel 初始化
    log_info "执行 Laravel 初始化..."
    docker exec cert-php sh -c "
        cd /www/cert_manager/backend &&
        php artisan key:generate &&
        php artisan migrate --force &&
        php artisan storage:link
    " 2>/dev/null || log_warning "Laravel 初始化可能需要手动完成"
    
    log_success "服务启动完成"
}

# 显示访问信息
show_access_info() {
    echo
    log_success "=================================================="
    log_success " 证书管理系统 Docker 部署完成！"
    log_success "=================================================="
    echo
    log_info "版本信息: $VERSION"
    log_info "部署目录: $DEPLOY_ROOT"
    echo
    log_info "访问地址:"
    log_info "  管理端: http://your-domain/admin"
    log_info "  用户端: http://your-domain/user"
    log_info "  简易端: http://your-domain/easy"
    log_info "  API接口: http://your-domain/api"
    echo
    log_info "数据库信息:"
    log_info "  主机: mysql (容器内) / localhost:3306 (宿主机)"
    log_info "  数据库: cert_manager"
    log_info "  用户名: cert_user"
    log_info "  密码: cert@2024"
    echo
    log_info "Redis信息:"
    log_info "  主机: redis (容器内) / localhost:6379 (宿主机)"
    log_info "  密码: 无"
    echo
    log_info "常用命令:"
    log_info "  查看容器: docker ps"
    log_info "  查看日志: docker logs cert-php"
    log_info "  进入PHP容器: docker exec -it cert-php bash"
    log_info "  停止服务: docker compose down"
    log_info "  重启服务: docker compose restart"
    echo
    log_warning "请记得配置域名解析和防火墙规则！"
}

# 主函数
main() {
    log_info "证书管理系统 Docker 生产环境部署"
    echo
    
    # 检查 Docker 环境
    check_docker
    
    # 清理旧环境（如果需要）
    clean_docker_environment
    
    # 创建目录
    create_directories
    
    # 拉取生产代码
    echo
    pull_production_code
    
    # 部署文件
    echo
    deploy_files
    
    # 生成配置文件
    echo
    generate_docker_compose
    generate_nginx_config
    generate_php_config
    
    # 初始化 Laravel
    echo
    initialize_laravel
    
    # 启动服务
    echo
    start_services
    
    # 显示访问信息
    show_access_info
}

# 执行主函数
main "$@"